﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;

using Moe.ECamel.Common.Contracts;
using Moe.ECamel.Common.Entities;
using Moe.ECamel.Common.Security;
using Moe.ECamel.Common.Utils;

namespace Moe.ECamel.Server.BL
{
	/// <summary>
	/// Encapsulates system business logic operations.
	/// </summary>
	public class SystemBL : ECamelBL
	{
		/// <summary>
		/// Default constructor for business logic component.
		/// </summary>
		/// <param name="dataContext">Data context to be used by this component's operations.</param>
		public SystemBL(ECamelDataContext dataContext)
			: base(dataContext)
		{
		}

		/// <summary>
		/// Load initial system startup information.
		/// </summary>
		/// <returns>Startup information.</returns>
		public ECamelSystemInfo GetSystemInfo()
		{
			// If data connection is invalid, abort:
			if (!dataContext.DatabaseExists())
				return null;

			// Initialize result:
			ECamelSystemInfo systemInfo = new ECamelSystemInfo();

			// Setup load options:
			DataLoadOptions loadOptions = new DataLoadOptions();
			loadOptions.LoadWith<SubscriptionType>(st => st.SubscriptionTypeItemTypeInfos);
			loadOptions.LoadWith<SubscriptionTypeItemTypeInfo>(a => a.ItemType);
			dataContext.LoadOptions = loadOptions;

			// Load all roles:
			systemInfo.Roles = dataContext.Roles.ToDictionary(r => r.RoleId);
			// Load all messages:
			systemInfo.Messages = dataContext.Messages.ToDictionary(m => m.MessageId);
			// Load all library types:
			systemInfo.LibraryTypes = dataContext.LibraryTypes.ToDictionary(l => l.LibraryTypeId);
			// Load all subscription types:
			systemInfo.SubscriptionTypes = dataContext.SubscriptionTypes.ToDictionary(st => st.SubscriptionTypeId);
			// Load item types:
			systemInfo.ItemTypesList = dataContext.ItemTypes.ToList();
			// Load item types properties:
			systemInfo.ItemPropertyTypes = dataContext.ItemPropertyTypes.ToList();

			return systemInfo;
		}

		/// <summary>
		/// Load DB with basic system information.
		/// </summary>
		public void GenerateSystemBasicInfo()
		{
			#region Initialize code tables

			// Initialize libraries types:
			dataContext.LibraryTypes.InsertOnSubmit(new LibraryType { LibraryTypeId = 1, LibraryTypeName = "מחוזית" });
			dataContext.LibraryTypes.InsertOnSubmit(new LibraryType { LibraryTypeId = 2, LibraryTypeName = "עירונית" });
			dataContext.LibraryTypes.InsertOnSubmit(new LibraryType { LibraryTypeId = 3, LibraryTypeName = "שכונתית" });

			// Initialize item types:
			ItemType book = new ItemType { ItemTypeId = 1, ItemTypeName = "ספר" };
			ItemType audioCD = new ItemType { ItemTypeId = 2, ItemTypeName = "דיסק מוזיקה" };
			ItemType videoTape = new ItemType { ItemTypeId = 3, ItemTypeName = "קלטת וידאו" };
			dataContext.ItemTypes.InsertAllOnSubmit(new ItemType[] { book, audioCD, videoTape });

			#endregion

			#region Initialize default subscription type

			SubscriptionType st = new SubscriptionType
			{
				SubscriptionTypeId = 1,
				SubscriptionTypeName = "רגיל",
				CreatedOn = SystemContainer.Clock.Today,
				Duration = 12,
				Active = true,
			};
			st.SubscriptionTypeItemTypeInfos.Add(new SubscriptionTypeItemTypeInfo { SubscriptionType = st, 
				ItemType = book, 
				PricePerUnit = 50, 
				DepositFeePerUnit = 150, 
				MaxRentalDays = 3, 
				FinePerExtraRentalDay = 1});
			st.SubscriptionTypeItemTypeInfos.Add(new SubscriptionTypeItemTypeInfo { SubscriptionType = st, 
				ItemType = audioCD, 
				PricePerUnit = 75, 
				DepositFeePerUnit = 225, 
				MaxRentalDays = 3, 
				FinePerExtraRentalDay = 1 });
			st.SubscriptionTypeItemTypeInfos.Add(new SubscriptionTypeItemTypeInfo { SubscriptionType = st, 
				ItemType = videoTape, 
				PricePerUnit = 92, 
				DepositFeePerUnit = 302, 
				MaxRentalDays = 3, 
				FinePerExtraRentalDay = 1 });
			dataContext.SubscriptionTypes.InsertOnSubmit(st);

			#endregion

			#region Initialize property types

			#region Book properties

			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			{
				ItemPropertyTypeId = 1,
				ItemPropertyTypeName = "מחבר",
				ItemType = book,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			{
				ItemPropertyTypeId = 2,
				ItemPropertyTypeName = "הוצאה",
				ItemType = book,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 3,
				ItemPropertyTypeName = "ז'אנר",
				ItemType = book,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 4,
				ItemPropertyTypeName = "עמודים",
				ItemType = book,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 5,
				ItemPropertyTypeName = "תאריך פרסום",
				ItemType = book,
			});

			#endregion

			#region Audio CD Properties

			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 6,
				ItemPropertyTypeName = "זמר/להקה",
				ItemType = audioCD,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 7,
				ItemPropertyTypeName = "ז'אנר",
				ItemType = audioCD,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 8,
				ItemPropertyTypeName = "אורך )בדקות(",
				ItemType = audioCD,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 9,
				ItemPropertyTypeName = "תאריך פרסום",
				ItemType = audioCD,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 10,
				ItemPropertyTypeName = "רצועה",
				ItemType = audioCD,
			});

			#endregion

			#region VideoTape properties

			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 11,
				ItemPropertyTypeName = "במאי",
				ItemType = videoTape,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 12,
				ItemPropertyTypeName = "שחקן",
				ItemType = videoTape,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 13,
				ItemPropertyTypeName = "ז'אנר",
				ItemType = videoTape,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 14,
				ItemPropertyTypeName = "אורך )בדקות(",
				ItemType = videoTape,
			});
			dataContext.ItemPropertyTypes.InsertOnSubmit(new ItemPropertyType
			                                             	{
				ItemPropertyTypeId = 15,
				ItemPropertyTypeName = "תאריך פרסום",
				ItemType = videoTape,
			});

			#endregion

			#endregion

			#region Initialize Messages

			#region System Messages

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.UnexpectedError,
				MessageTypeId = MessageTypes.Error,
				Caption = "שגיאה לא מוכרת",
				Text = "אירעה שגיאה לא מוכרת במערכת:" + Environment.NewLine + "{0}"
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.SecurityInvalidCredentials,
				MessageTypeId = MessageTypes.Error,
				Caption = "אבטחה",
				Text = "שם המשתמש או הסיסמה אינם תקינים."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.SecurityMaxAttemptsReached,
				MessageTypeId = MessageTypes.Error,
				Caption = "אבטחה",
				Text = "אירעו יותר מדי נסיונות כושלים להיכנס למערכת."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.LoginInvalidInactiveLibrary,
				MessageTypeId = MessageTypes.Error,
				Caption = "אבטחה",
				Text = "לא ניתן להיכנס למערכת מכיוון שהספריה שלך ({0}) אינה פעילה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.SecurityInsufficientPermissions,
				MessageTypeId = MessageTypes.Error,
				Caption = "אבטחה",
				Text = "אינך מורשה לבצע פעולה זו."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.ChangePasswordFailedInvalidOldPassword,
				MessageTypeId = MessageTypes.Error,
				Caption = "אבטחה",
				Text = "לא ניתן להחליף סיסמה - הסיסמה הישנה אינה נכונה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.ChangePasswordFailedPasswordsNotMatch,
				MessageTypeId = MessageTypes.Error,
				Caption = "אבטחה",
				Text = "לא ניתן להחליף סיסמה - אישור הסיסמה שונה מהסיסמה."
			});

			#endregion

			#region Library Messages

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.LibraryInvalidMissingFields,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות ספריה",
				Text = "הספריה אינה תקינה - שדות חובה לא הוזנו:" + Environment.NewLine + "{0}"
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.LibraryInvalidDuplicateName,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות ספריה",
				Text = "הספריה אינה תקינה:" + Environment.NewLine + "קיימת ספריה אחרת בשם זה."
			});

			#endregion

			#region User Messages

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.UserInvalidMissingFields,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות משתמש",
				Text = "המשתמש אינו תקין - שדות חובה לא הוזנו:" + Environment.NewLine + "{0}"
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.UserInvalidDuplicateName,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות משתמש",
				Text = "המשתמש אינו תקין:" + Environment.NewLine + "קיים משתמש אחר בשם זה."
			});

			#endregion

			#region Employee Messages

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.EmployeeInvalidMissingFields,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות עובד",
				Text = "העובד אינו תקין - שדות חובה לא הוזנו:" + Environment.NewLine + "{0}"
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.EmployeeInvalidNegativeSalary,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות עובד",
				Text = "העובד אינו תקין - המשכורת אינה יכולה להיות שלילית:"
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.EmployeeCannotChangeManagerStatus,
				MessageTypeId = MessageTypes.Warning,
				Caption = "שינוי סטטוס עובד",
				Text = "לא ניתן לשנות ססטוס של מנהל."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.EmployeeManagerCannotBeInactive,
				MessageTypeId = MessageTypes.Warning,
				Caption = "שינוי מנהל",
				Text = "עובד לא פעיל אינו יכול להיות מנהל."
			});

			#endregion

			#region Customer Messages

			#endregion

			#region Subscriptions Messages

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.SubscriptionInvalidDuplicateActive,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות מנוי",
				Text = "המנוי אינו תקין:" + Environment.NewLine + "קיים מנוי פעיל אחר ללקוח זה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.SubscriptionInvalidExpired,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות מנוי",
				Text = "לא ניתן להפעיל מנוי שפג תוקפו."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.SubscriptionDeleteConfirmation,
				MessageTypeId = MessageTypes.Question,
				Caption = "מחיקת מנוי",
				Text = "האם אתה בטוח שאתה רוצה למחוק את המנוי?"
			});

			#endregion

			#region Item Messages

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.ItemInvalidMissingFields,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות פריט",
				Text = "הפריט אינו תקין - שדות חובה לא הוזנו:" + Environment.NewLine + "{0}"
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.ItemInvalidDuplicateCatalogNumber,
				MessageTypeId = MessageTypes.Warning,
				Caption = "בדיקת תקינות הפריט",
				Text = "הפריט אינו תקין:" + Environment.NewLine + "המספר הקטלוגי נמצא בשימוש פריט אחר."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.ItemDeleteConfirmation,
				MessageTypeId = MessageTypes.Question,
				Caption = "מחיקת פריט",
				Text = "האם אתה בטוח שאתה רוצה למחוק את הפריט {0}?"
			});

			#endregion

			#region Rental Messages

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalSuccessful,
				MessageTypeId = MessageTypes.Info,
				Caption = "השכרה",
				Text = "ההשכרה הסתיימה בהצלחה. יש להחזיר את הפריט לספריה עד לתאריך {0}."
			});

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalInvalidNoActiveSubscription,
				MessageTypeId = MessageTypes.Warning,
				Caption = "השכרה",
				Text = "לא ניתן להשכיר ללא מנוי פעיל."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalInvalidExceedsSubscription,
				MessageTypeId = MessageTypes.Warning,
				Caption = "השכרה",
				Text = "המנוי אינו מאפשר השכרת פריט נוסף מסוג זה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalInvalidNoAvailableInventory,
				MessageTypeId = MessageTypes.Warning,
				Caption = "השכרה",
				Text = "אין עותק זמין של הפריט המבוקש בספריה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalReservationRequestAdded,
				MessageTypeId = MessageTypes.Info,
				Caption = "השכרה",
				Text = "בקשתך נרשמה ברשימת ההמתנה. כאשר יתפנה עותק תישלח אלייך הודעה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalCustomerHasDebt,
				MessageTypeId = MessageTypes.Question,
				Caption = "השכרה",
				Text = "ללקוח נצבר חוב בסך {0} שקלים חדשים. האם להמשיך בפעולת ההשכרה למרות החוב?"
			});


			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalReturnInvalidMissingFields,
				MessageTypeId = MessageTypes.Warning,
				Caption = "החזרה",
				Text = "שדות חובה לא הוזנו:" + Environment.NewLine + "{0}"
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalReturnInvalidAlreadyRetuend,
				MessageTypeId = MessageTypes.Warning,
				Caption = "החזרה",
				Text = "לא ניתן להחזיר השכרה שכבר הוחזרה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalReturnInvalidReturnBeforeRental,
				MessageTypeId = MessageTypes.Warning,
				Caption = "החזרה",
				Text = "תאריך ההחזרה שהוזן מוקדם מתאריך ההשכרה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalReturnFineForLateReturn,
				MessageTypeId = MessageTypes.Question,
				Caption = "החזרה",
				Text = "עליך לשלם קנס בסך {0} שקלים חדשים בגין החזרה מאוחרת. האם אתה מעוניין לשלם את הקנס כעת?"
			});

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalFineInvalidNotReturnedYet,
				MessageTypeId = MessageTypes.Warning,
				Caption = "החזרה",
				Text = "לא ניתן לשלם קנס - הפריט טרם הוחזר."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalFineInvalidNoFineToPay,
				MessageTypeId = MessageTypes.Warning,
				Caption = "החזרה",
				Text = "אין צורך לשלם קנס."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.RentalFineInvalidAlreadyPayed,
				MessageTypeId = MessageTypes.Warning,
				Caption = "החזרה",
				Text = "הקנס כבר שולם."
			});

			#endregion

			#region Inventory Messages

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.InventoryTrasferFailed,
				MessageTypeId = MessageTypes.Warning,
				Caption = "מלאי",
				Text = "לא נמצא עותק פנוי בספריה אחרת."
			});

			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.InventoryTrasferSucceeded,
				MessageTypeId = MessageTypes.Info,
				Caption = "מלאי",
				Text = "הועבר עותק של  \"{0}\" (מק\"ט {1}) מספריה {2} לספריה {3}."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.InventoryNewCopyRequestCreated,
				MessageTypeId = MessageTypes.Info,
				Caption = "מלאי",
				Text = "בקשה לעותק נוסף של הפריט נרשמה."
			});
			dataContext.Messages.InsertOnSubmit(new Message
			                                    	{
				MessageId = MessageIds.InventoryNewCopyAdded,
				MessageTypeId = MessageTypes.Info,
				Caption = "מלאי",
				Text = "בעקבות הבקשה הוחלט לרכוש עותק נוסף של הפריט. ניתן להשכיר כעת."
			});


			#endregion 

			#endregion

			#region Initialize Roles and Operations

			// Initialize operations:
			var libraryView = new Operation { OperationId = 1001, OperationName = Operations.LibraryView };
			var libraryEdit = new Operation { OperationId = 1002, OperationName = Operations.LibraryEdit };
			var libraryAdd = new Operation { OperationId = 1003, OperationName = Operations.LibraryAdd };
			var libraryChangeStatus = new Operation { OperationId = 1004, OperationName = Operations.LibraryChangeStatus };
			var employeeView = new Operation { OperationId = 1101, OperationName = Operations.EmployeeView };
			var employeeEdit = new Operation { OperationId = 1102, OperationName = Operations.EmployeeEdit };
			var employeeAdd = new Operation { OperationId = 1103, OperationName = Operations.EmployeeAdd };
			var employeeChangeStatus = new Operation { OperationId = 1104, OperationName = Operations.EmployeeChangeStatus };
			var employeeChangeManager = new Operation { OperationId = 1105, OperationName = Operations.EmployeeChangeManager };
			var customerView = new Operation { OperationId = 1201, OperationName = Operations.CustomerView };
			var customerEdit = new Operation { OperationId = 1202, OperationName = Operations.CustomerEdit };
			var customerAdd = new Operation { OperationId = 1203, OperationName = Operations.CustomerAdd };
			var subscriptionView = new Operation { OperationId = 1301, OperationName = Operations.SubscriptionView };
			var subscriptionEdit = new Operation { OperationId = 1302, OperationName = Operations.SubscriptionEdit };
			var subscriptionAdd = new Operation { OperationId = 1303, OperationName = Operations.SubscriptionAdd };
			var itemView = new Operation { OperationId = 1401, OperationName = Operations.ItemView };
			var itemEdit = new Operation { OperationId = 1402, OperationName = Operations.ItemEdit };
			var itemAdd = new Operation { OperationId = 1403, OperationName = Operations.ItemAdd };
			var inventoryAdd = new Operation { OperationId = 1501, OperationName = Operations.InventoryAdd};
			var inventoryDelete = new Operation { OperationId = 1502, OperationName = Operations.InventoryDelete };
			var inventoryTransfer = new Operation { OperationId = 1503, OperationName = Operations.InventoryTransfer };
			var inventoryRequestNewCopy = new Operation {OperationId = 1504, OperationName = Operations.InventoryRequestNewCopy};
			var inventoryRequestReserve = new Operation { OperationId = 1505, OperationName = Operations.InventoryRequestReserve};
			var rentalView = new Operation { OperationId = 1601, OperationName = Operations.RentalView };
			var rentalRent = new Operation { OperationId = 1602, OperationName = Operations.RentalRent };
			var rentalReturn = new Operation { OperationId = 1603, OperationName = Operations.RentalReturn };
			var rentalPayFine = new Operation { OperationId = 1604, OperationName = Operations.RentalPayFine};
			var paymentView = new Operation { OperationId = 1701, OperationName = Operations.PaymentView };
			var reportCustomersDebts = new Operation { OperationId = 1801, OperationName = Operations.ReportCustomersDebts };
			var reportTopRentedItems = new Operation { OperationId = 1802, OperationName = Operations.ReportTopRentedItems };

			var allOperations = new Operation[] { 
				libraryView, libraryEdit, libraryAdd, libraryChangeStatus,
				employeeView, employeeEdit, employeeAdd, employeeChangeStatus, employeeChangeManager,
				customerView, customerEdit, customerAdd, 
				subscriptionView, subscriptionEdit, subscriptionAdd, 
				itemView, itemEdit, itemAdd, 
				inventoryAdd, inventoryDelete, inventoryTransfer, inventoryRequestNewCopy, inventoryRequestReserve,
				rentalView, rentalRent, rentalReturn, rentalPayFine,
				paymentView,
				reportCustomersDebts, reportTopRentedItems
			};
			dataContext.Operations.InsertAllOnSubmit(allOperations);

			// Initialize roles and assign operations:
			var customer = CreateRole(Roles.Customer, "לקוח", null, libraryView, customerView, subscriptionView, 
				itemView, rentalView, paymentView);

			var employee = CreateRole(Roles.Employee, "עובד", customer,
				customerAdd, customerEdit, subscriptionAdd, subscriptionEdit,
				rentalRent, rentalReturn, rentalPayFine, inventoryTransfer, inventoryRequestNewCopy, inventoryRequestReserve);


			var manager = CreateRole(Roles.Manager, "מנהל ספריה", employee, 
				libraryEdit, itemAdd, itemEdit, inventoryAdd, inventoryDelete,
				employeeAdd, employeeEdit, employeeChangeStatus, employeeView, 
				reportCustomersDebts, reportTopRentedItems);

			var admin = CreateRole(Roles.Admin, "מנהל ארצי", null, allOperations);

			Role[] allRoles = new Role[] { admin, manager, employee, customer};
			dataContext.Roles.InsertAllOnSubmit(allRoles);

			#endregion
		}

		private static Role CreateRole(int roleId, String roleName, Role baseRole, params Operation[] operations)
		{
			var role = new Role {RoleId = roleId, RoleName = roleName};
			foreach (Operation operation in operations)
				role.RoleOperations.Add(new RoleOperations { Role = role, Operation = operation });

			if (baseRole != null)
				foreach (var baseOperation in baseRole.RoleOperations)
					role.RoleOperations.Add(new RoleOperations {Role = role, Operation = baseOperation.Operation});

			return role;
		}

		/// <summary>
		/// Deletes all user-entered information from the system.
		/// </summary>
		public void DeleteUserData()
		{
			dataContext.Customers.ClearOnSubmit();
			dataContext.Employees.ClearOnSubmit();
			dataContext.InventoryRequests.ClearOnSubmit();
			dataContext.Inventories.ClearOnSubmit();
			dataContext.Items.ClearOnSubmit();
			dataContext.ItemProperties.ClearOnSubmit();
			dataContext.ItemReservations.ClearOnSubmit();
			dataContext.Libraries.ClearOnSubmit();
			dataContext.Rentals.ClearOnSubmit();
			dataContext.SubscriptionItemTypeInfos.ClearOnSubmit();
			dataContext.Subscriptions.ClearOnSubmit();
			dataContext.MailMessages.ClearOnSubmit();
			dataContext.Payments.ClearOnSubmit();

			// Find admin user id:
			int adminUserId = (from ur in dataContext.UserRoles
							   where ur.RoleId == Roles.Admin
							   select ur.UserId).FirstOrDefault();

			// Delete all non-admin users and roles:
			var usersToDelete = (from u in dataContext.Users where u.UserId != adminUserId select u);
			dataContext.Users.DeleteAllOnSubmit(usersToDelete);
			var userRolesToDelete = (from ur in dataContext.UserRoles where ur.UserId != adminUserId select ur);
			dataContext.UserRoles.DeleteAllOnSubmit(userRolesToDelete);
		}
	}
}